package com.xyrl.project.common.base.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xyrl.common.core.properties.XyrlProperties;
import com.xyrl.common.util.ObjectUtil;
import com.xyrl.common.util.RedisUtil;
import com.xyrl.common.util.StringUtil;
import com.xyrl.project.common.authentication.JWTUtil;
import com.xyrl.project.common.authentication.LoginInfo;
import com.xyrl.project.common.base.service.CacheService;
import com.xyrl.project.common.constant.XyrlConstant;
import com.xyrl.project.common.csr.entity.CsrUser;
import com.xyrl.project.common.system.dao.UserMapper;
import com.xyrl.project.common.system.entity.*;
import com.xyrl.project.common.system.service.MenuService;
import com.xyrl.project.common.system.service.RoleService;
import com.xyrl.project.common.system.service.UserConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service("cacheService")
public class CacheServiceImpl implements CacheService {
    @Autowired
    private RoleService roleService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private UserConfigService userConfigService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ObjectMapper mapper;

    @Autowired
    private XyrlProperties properties;


    @Override
    public void testConnect() throws Exception {
        boolean isKey = RedisUtil.hasKey("test");
        log.debug("reids 配置正常");
    }

    @Override
    public User getUser(String username) throws Exception {
        String userString = RedisUtil.getData(XyrlConstant.USER_CACHE_PREFIX + username);
        if (StringUtils.isBlank(userString)) {
            throw new Exception();
        } else {
            return this.mapper.readValue(userString, User.class);
        }
    }

    @Override
    public CsrUser getCustomerUser(String username) throws Exception {
        String userString = RedisUtil.getData(XyrlConstant.CUSTOMER_USER_CACHE_PREFIX + username);
        if (StringUtils.isBlank(userString)) {
            throw new Exception();
        } else {
            return this.mapper.readValue(userString, CsrUser.class);
        }
    }

    @Override
    public List<Role> getRoles(String username) throws Exception {
        String roleListString = RedisUtil.getData(XyrlConstant.USER_ROLE_CACHE_PREFIX + username);
        if (StringUtils.isBlank(roleListString)) {
            throw new Exception();
        } else {
            JavaType type = mapper.getTypeFactory().constructParametricType(List.class, Role.class);
            return this.mapper.readValue(roleListString, type);
        }
    }

    @Override
    public List<Menu> getPermissions(String username) throws Exception {
        String permissionListString = RedisUtil.getData(XyrlConstant.USER_PERMISSION_CACHE_PREFIX + username);
        if (StringUtils.isBlank(permissionListString)) {
            throw new Exception();
        } else {
            JavaType type = mapper.getTypeFactory().constructParametricType(List.class, Menu.class);
            return this.mapper.readValue(permissionListString, type);
        }
    }

    @Override
    public UserConfig getUserConfig(String userId) throws Exception {
        String userConfigString = RedisUtil.getData(XyrlConstant.USER_CONFIG_CACHE_PREFIX + userId);
        if (StringUtils.isBlank(userConfigString)) {
            throw new Exception();
        } else {
            return this.mapper.readValue(userConfigString, UserConfig.class);
        }
    }

    @Override
    public void saveUser(User user) throws Exception {
        String username = user.getAccount();
        this.deleteUser(username);
        RedisUtil.setData(XyrlConstant.USER_CACHE_PREFIX + username, mapper.writeValueAsString(user));
    }

    @Override
    public void saveUser(String username) throws Exception {
        QueryWrapper<User> query = new QueryWrapper<>();
        query.lambda().eq(User::getAccount, username).eq(User::getIsDelete, XyrlConstant.NO);
        User user = userMapper.selectOne(query);
        this.deleteUser(username);
        RedisUtil.setData(XyrlConstant.USER_CACHE_PREFIX + username, mapper.writeValueAsString(user));
    }

    @Override
    public void saveRoles(String username) throws Exception {
        List<Role> roleList = this.roleService.findUserRole(username);
        //缓存数据
        saveRoles(username, roleList);
    }

    @Override
    public void saveRoles(String username, List<Role> roleList) throws Exception {
        if (ObjectUtil.isNotEmpty(roleList)) {
            this.deleteRoles(username);
            RedisUtil.setData(XyrlConstant.USER_ROLE_CACHE_PREFIX + username, mapper.writeValueAsString(roleList));
        }
    }

    @Override
    public void savePermissions(String username) throws Exception {
        List<Menu> permissionList = this.menuService.findUserPermissions(username);
        //缓存数据
        savePermissions(username, permissionList);
    }

    @Override
    public void savePermissions(String username, List<Menu> lists) throws Exception {
        if (ObjectUtil.isNotEmpty(lists)) {
            this.deletePermissions(username);
            RedisUtil.setData(XyrlConstant.USER_PERMISSION_CACHE_PREFIX + username, mapper.writeValueAsString(lists));
        }
    }

    @Override
    public void saveUserConfigs(String userId) throws Exception {
        UserConfig userConfig = this.userConfigService.findByUserId(userId);
        //缓存数据
        saveUserConfigs(userId, userConfig);
    }

    @Override
    public void saveUserConfigs(String userId, UserConfig userConfig) throws Exception {
        if (ObjectUtil.isNotEmpty(userConfig)) {
            this.deleteUserConfigs(userId);
            RedisUtil.setData(XyrlConstant.USER_CONFIG_CACHE_PREFIX + userId, mapper.writeValueAsString(userConfig));
        }
    }

    @Override
    public void deleteUser(String username) {
        RedisUtil.delKey(XyrlConstant.USER_CACHE_PREFIX + username);
    }

    @Override
    public void deleteRoles(String username) {
        RedisUtil.delKey(XyrlConstant.USER_ROLE_CACHE_PREFIX + username);
    }

    @Override
    public void deletePermissions(String username) {
        RedisUtil.delKey(XyrlConstant.USER_PERMISSION_CACHE_PREFIX + username);
    }

    @Override
    public void deleteUserConfigs(String userId) {
        RedisUtil.delKey(XyrlConstant.USER_CONFIG_CACHE_PREFIX + userId);
    }


    /**
     * 添加在线用户至缓存
     *
     * @param ip    登录ip 信息
     * @param info  登录用户信息
     * @param token 当前token值
     */
    @Override
    public String cacheLoginUser(String ip, LoginInfo info, String token) {
        ActiveUser activeUser = createActiveiUser(info.getLoginName(), info.getUserType(), token, ip);
        //缓存在线用户token
        String cacheUserKey = StringUtil.concat(info.getUserType(), ":", info.getLoginName());
        //超时时间
        long expireTime = System.currentTimeMillis() / 1000 + properties.getShiro().getJwtTimeOut();
        log.debug("登录超时间:{},token 有效时间:{}",expireTime,properties.getShiro().getJwtTimeOut());
        try {
            // zset 存储登录用户，score 为过期时间戳
            RedisUtil.setSortSet(XyrlConstant.ACTIVE_USERS_ZSET_PREFIX, cacheUserKey, expireTime);
            //添加在线用户数据
            RedisUtil.setMap(XyrlConstant.ACTIVE_USER_MAP_PREFIX, cacheUserKey, mapper.writeValueAsString(activeUser));
        } catch (Exception e) {
            log.error("添加缓存异常", e);
        }

        //添加至map
        RedisUtil.setMap(XyrlConstant.ACTIVE_USER_TOKEN, cacheUserKey, token);
        //缓存登录用户
        JWTUtil.cacheToken(token, cacheUserKey);
        return activeUser.getId();
    }

    /**
     * 生成在线用户数据
     *
     * @param userName 登录帐号
     * @param userType 用户类型
     * @param token    用户token
     * @param ip       登录ip
     * @return
     */
    private ActiveUser createActiveiUser(String userName, String userType, String token, String ip) {
        // 构建在线用户
        ActiveUser activeUser = new ActiveUser();
        activeUser.setUsername(userName);
        activeUser.setIp(ip);
        activeUser.setToken(token);
        activeUser.setUserType(userType);
        return activeUser;
    }

    /**
     * 清除登录信息
     *
     * @param token
     */
    @Override
    public void clearCacheLoginUser(String token) {
        //token 为空时不做处理
        if(ObjectUtil.isEmpty(token)){
            return;
        }
        //取得登录信息
        LoginInfo info = JWTUtil.getLoginInfo(token);
        if (ObjectUtil.isNotEmpty(info)) {
            //缓存登陆用户信息key
            String cacheUserKey = StringUtil.concat(info.getUserType(), ":", info.getLoginName());
            // zset 存储登录用户，score 为过期时间戳
            RedisUtil.delSortSet(XyrlConstant.ACTIVE_USERS_ZSET_PREFIX, cacheUserKey);
            //添加在线用户数据
            RedisUtil.delMap(XyrlConstant.ACTIVE_USER_MAP_PREFIX, cacheUserKey);
            //添加至map
            RedisUtil.delMap(XyrlConstant.ACTIVE_USER_TOKEN, cacheUserKey);
            //缓存登录用户
            JWTUtil.clearToken(token);
            //清除用户权限
            deletePermissions(info.getLoginName());
            //清除用户登录信息
            deleteUser(info.getLoginName());
            //清除用户角色
            deleteRoles(info.getLoginName());
        }
    }

}
